package services

import (
	"b2c-delivery-optimization/internal/algorithm"
	"b2c-delivery-optimization/internal/model"
	"fmt"
	"os"
	"path/filepath"
	"time"

	"github.com/wcharczuk/go-chart/v2"
	"github.com/wcharczuk/go-chart/v2/drawing"
)

// VisualizationService 可视化服务
type VisualizationService struct {
	outputDir string
	colors    []drawing.Color
}

// NewVisualizationService 创建可视化服务
func NewVisualizationService(outputDir string) *VisualizationService {
	return &VisualizationService{
		outputDir: outputDir,
		colors: []drawing.Color{
			{R: 0, G: 128, B: 255, A: 255}, // 蓝色
			{R: 0, G: 255, B: 0, A: 255},   // 绿色
			{R: 255, G: 165, B: 0, A: 255}, // 橙色
			{R: 255, G: 0, B: 0, A: 255},   // 红色
			{R: 128, G: 0, B: 128, A: 255}, // 紫色
		},
	}
}

// GenerateWaveDistributionChart 生成波次分布图表
func (s *VisualizationService) GenerateWaveDistributionChart(waves [][]model.Order) error {
	// 准备数据
	var values []chart.Value
	for i, wave := range waves {
		values = append(values, chart.Value{
			Value: float64(len(wave)),
			Label: fmt.Sprintf("波次%d", i+1),
		})
	}

	// 创建柱状图
	graph := chart.BarChart{
		Title: "波次订单分布",
		Background: chart.Style{
			Padding: chart.Box{
				Top: 20,
			},
		},
		Height:   400,
		BarWidth: 60,
		Bars:     values,
		XAxis: chart.Style{
			StrokeWidth: 1,
			StrokeColor: drawing.Color{R: 0, G: 0, B: 0, A: 255},
		},
		YAxis: chart.YAxis{
			Style: chart.Style{
				StrokeWidth: 1,
				StrokeColor: drawing.Color{R: 0, G: 0, B: 0, A: 255},
			},
		},
	}

	// 保存图表
	filename := filepath.Join(s.outputDir, "wave_distribution.png")
	return s.saveBarChart(&graph, filename)
}

// GeneratePriorityDistributionChart 生成优先级分布图表
func (s *VisualizationService) GeneratePriorityDistributionChart(waves [][]model.Order) error {
	// 统计每个波次的优先级分布
	priorityDistribution := make([]map[int]int, len(waves))
	for i := range waves {
		priorityDistribution[i] = make(map[int]int)
		for _, order := range waves[i] {
			priorityDistribution[i][order.Priority]++
		}
	}

	// 准备数据
	var values []chart.Value
	for i, dist := range priorityDistribution {
		for priority, count := range dist {
			values = append(values, chart.Value{
				Value: float64(count),
				Label: fmt.Sprintf("波次%d-优先级%d", i+1, priority),
			})
		}
	}

	// 创建堆叠柱状图
	graph := chart.BarChart{
		Title: "波次优先级分布",
		Background: chart.Style{
			Padding: chart.Box{
				Top: 20,
			},
		},
		Height:   400,
		BarWidth: 60,
		Bars:     values,
		XAxis: chart.Style{
			StrokeWidth: 1,
			StrokeColor: drawing.Color{R: 0, G: 0, B: 0, A: 255},
		},
		YAxis: chart.YAxis{
			Style: chart.Style{
				StrokeWidth: 1,
				StrokeColor: drawing.Color{R: 0, G: 0, B: 0, A: 255},
			},
		},
	}

	// 保存图表
	filename := filepath.Join(s.outputDir, "priority_distribution.png")
	return s.saveBarChart(&graph, filename)
}

// GenerateLocationDistributionChart 生成位置分布图表
func (s *VisualizationService) GenerateLocationDistributionChart(waves [][]model.Order) error {
	// 准备数据
	var xValues []float64
	var yValues []float64
	var colors []drawing.Color

	for i, wave := range waves {
		for _, order := range wave {
			xValues = append(xValues, order.Location.Longitude)
			yValues = append(yValues, order.Location.Latitude)
			colors = append(colors, s.colors[i%len(s.colors)])
		}
	}

	// 创建散点图
	graph := chart.Chart{
		Title: "订单位置分布",
		Background: chart.Style{
			Padding: chart.Box{
				Top: 20,
			},
		},
		Height: 400,
		XAxis: chart.XAxis{
			Style: chart.Style{
				StrokeWidth: 1,
				StrokeColor: drawing.Color{R: 0, G: 0, B: 0, A: 255},
			},
		},
		YAxis: chart.YAxis{
			Style: chart.Style{
				StrokeWidth: 1,
				StrokeColor: drawing.Color{R: 0, G: 0, B: 0, A: 255},
			},
		},
		Series: []chart.Series{
			chart.ContinuousSeries{
				Style: chart.Style{
					StrokeColor: s.colors[0],
					FillColor:   s.colors[0],
				},
				XValues: xValues,
				YValues: yValues,
			},
		},
	}

	// 保存图表
	filename := filepath.Join(s.outputDir, "location_distribution.png")
	return s.saveChart(graph, filename)
}

// GenerateAlgorithmMetricsChart 生成算法指标图表
func (s *VisualizationService) GenerateAlgorithmMetricsChart(metrics []algorithm.AlgorithmMetrics) error {
	// 准备数据
	var times []time.Time
	var priorityScores []float64
	var locationScores []float64
	var balanceScores []float64

	for _, m := range metrics {
		times = append(times, m.Timestamp)
		priorityScores = append(priorityScores, m.PriorityScore)
		locationScores = append(locationScores, m.LocationScore)
		balanceScores = append(balanceScores, m.BalanceScore)
	}

	// 创建时间序列图
	graph := chart.Chart{
		Title: "算法指标变化",
		Background: chart.Style{
			Padding: chart.Box{
				Top: 20,
			},
		},
		Height: 400,
		XAxis: chart.XAxis{
			Style: chart.Style{
				StrokeWidth: 1,
				StrokeColor: drawing.Color{R: 0, G: 0, B: 0, A: 255},
			},
		},
		YAxis: chart.YAxis{
			Style: chart.Style{
				StrokeWidth: 1,
				StrokeColor: drawing.Color{R: 0, G: 0, B: 0, A: 255},
			},
		},
		Series: []chart.Series{
			chart.TimeSeries{
				Name: "优先级得分",
				Style: chart.Style{
					StrokeColor: s.colors[0],
					FillColor:   s.colors[0],
				},
				XValues: times,
				YValues: priorityScores,
			},
			chart.TimeSeries{
				Name: "位置得分",
				Style: chart.Style{
					StrokeColor: s.colors[1],
					FillColor:   s.colors[1],
				},
				XValues: times,
				YValues: locationScores,
			},
			chart.TimeSeries{
				Name: "平衡得分",
				Style: chart.Style{
					StrokeColor: s.colors[2],
					FillColor:   s.colors[2],
				},
				XValues: times,
				YValues: balanceScores,
			},
		},
	}

	// 保存图表
	filename := filepath.Join(s.outputDir, "algorithm_metrics.png")
	return s.saveChart(graph, filename)
}

// saveChart 保存图表到文件
func (s *VisualizationService) saveChart(graph chart.Chart, filename string) error {
	// 确保输出目录存在
	if err := os.MkdirAll(s.outputDir, 0755); err != nil {
		return fmt.Errorf("创建输出目录失败: %v", err)
	}

	// 创建文件
	f, err := os.Create(filename)
	if err != nil {
		return fmt.Errorf("创建文件失败: %v", err)
	}
	defer f.Close()

	// 渲染图表
	if err := graph.Render(chart.PNG, f); err != nil {
		return fmt.Errorf("渲染图表失败: %v", err)
	}

	return nil
}

// saveBarChart 保存柱状图到文件
func (s *VisualizationService) saveBarChart(graph *chart.BarChart, filename string) error {
	// 确保输出目录存在
	if err := os.MkdirAll(s.outputDir, 0755); err != nil {
		return fmt.Errorf("创建输出目录失败: %v", err)
	}

	// 创建文件
	f, err := os.Create(filename)
	if err != nil {
		return fmt.Errorf("创建文件失败: %v", err)
	}
	defer f.Close()

	// 渲染图表
	if err := graph.Render(chart.PNG, f); err != nil {
		return fmt.Errorf("渲染图表失败: %v", err)
	}

	return nil
}
